/**
    Copyright (c) 2010 yakiimo02
    Distributed under the New BSD License.
    See included license.txt or http://www.yakiimo3d.com/NewBSDLicense.txt
**/

#include "DXUT.h"
#include "GUI.h"
#include "ToneMapCS.h"
#include "HDRImageMgr.h"

#include <string>

#define IDC_MIDDLEKEY_TEXT                20001
#define IDC_MIDDLEKEY_SLIDER            20002
#define IDC_TONEMAP_ENABLE_CB            20003
#define IDC_CONTROL_BURNOUT_CB            20004
#define IDC_OPEN_FILE_DLG_BTN            20005

#define MIDDLEKEY_SLIDER_MAX            1000

GUI g_gui;

void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );


GUI::GUI() : m_pTxtHelper( NULL ), m_pOpenFileDlgButton( NULL ), m_pMiddleKeySlider( NULL ), m_pToneMapEnableCheckBox( NULL ), m_pControlBurnOutCheckBox( NULL )
{
}

/**
    @param pd3dDevice    [in]    D3D Device
*/
HRESULT GUI::Create( ID3D11Device* pd3dDevice )
{
    HRESULT hr = S_OK;

    ID3D11DeviceContext* pd3dImmediateContext = DXUTGetD3D11DeviceContext();
    V_RETURN( m_DialogResourceManager.OnD3D11CreateDevice( pd3dDevice, pd3dImmediateContext ) );
    m_pTxtHelper = new CDXUTTextHelper( pd3dDevice, pd3dImmediateContext, &m_DialogResourceManager, 15 );

     return hr;
}

/**
*/
void GUI::RegistGuiItems()
{
    m_SampleUI.Init( &m_DialogResourceManager );

    int nY = 0;

    // enable tonemapping checkbox
    m_SampleUI.AddCheckBox( IDC_TONEMAP_ENABLE_CB, L"Tone Mapping", 0, nY, 0, 24, g_toneMapCS.GetToneMapEnable(), 'T', false, &m_pToneMapEnableCheckBox );
    m_pToneMapEnableCheckBox->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );
    nY += 24;

    // enable control burnout checkbox
    m_SampleUI.AddCheckBox( IDC_CONTROL_BURNOUT_CB, L"Control BurnOut", 0, nY, 0, 24, g_toneMapCS.GetControlBurnOut(), 'B', false, &m_pControlBurnOutCheckBox );
    m_pToneMapEnableCheckBox->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );
    nY += 24;
    
    // middle key slider
    m_SampleUI.AddStatic( IDC_MIDDLEKEY_TEXT, L"Middle Key", 0, nY, 150, 24 );
    nY += 24;
    m_SampleUI.AddSlider( IDC_MIDDLEKEY_SLIDER, 0, nY, 128, 24, 0, MIDDLEKEY_SLIDER_MAX, 180, false, &m_pMiddleKeySlider );
    SetMiddleKeyValue();
    nY += 24;

    // load texture button
    m_SampleUI.AddButton( IDC_OPEN_FILE_DLG_BTN, L"Load Texture", 0, nY, 150, 24, 'L', true, &m_pOpenFileDlgButton );
    m_pOpenFileDlgButton->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );

    m_SampleUI.SetCallback( OnGUIEvent ); 
}

/**
    @param fElapsedTime        [in]        elapsed time
*/
void GUI::FrameRender( float fElapsedTime )
{
    m_SampleUI.OnRender( fElapsedTime );
    RenderText();
}

/**
*/
void GUI::RenderText()
{
    wchar_t strMsg[ 256 ];

    m_pTxtHelper->Begin();
    m_pTxtHelper->SetInsertionPos( 2, 0 );
    m_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
    m_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) );
    m_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() );

    const MeasureLuminanceCS* pMeasureLuminanceCS = g_toneMapCS.GetpMeasureLuminanceCS();

    swprintf_s( strMsg, L"MiddleKey: %f LogAvgLum: %f LumMax: %f", g_toneMapCS.GetMiddleKey(), pMeasureLuminanceCS->GetLogAvgLum(), pMeasureLuminanceCS->GetLumMax() );
    m_pTxtHelper->DrawTextLine( strMsg );

    m_pTxtHelper->End();
}

/**
    @param pd3dDevice        [in]    D3D Device
    @param pBackBufferDesc    [in]    Description of backbuffer
*/
HRESULT GUI::ResizedSwapChain( ID3D11Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc )
{
    HRESULT hr = S_OK;
    V_RETURN( m_DialogResourceManager.OnD3D11ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );

    m_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width - 170, pBackBufferSurfaceDesc->Height - 280 );
    m_SampleUI.SetSize( 150, 110 );

    return hr;
}

/**
*/
void GUI::Destroy()
{
    m_DialogResourceManager.OnD3D11DestroyDevice();
    SAFE_DELETE( m_pTxtHelper );    
}

/**
*/
LRESULT GUI::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
{
    // Pass messages to dialog resource manager calls so GUI state is updated correctly
    *pbNoFurtherProcessing = m_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;

    *pbNoFurtherProcessing = m_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;    

    return 0;
}

/**
    Looking at good old OPENFILENAME
    http://msdn.microsoft.com/en-us/library/ms646829%28VS.85%29.aspx#open_file
    gave me a link to the new Vista way of doing a FileOpenDialog. Since my app is DX11-based, 
    no need to support XP, so I can use Vista's IFileOpenDialog.
    http://msdn.microsoft.com/en-us/library/bb776913%28VS.85%29.aspx#usage
*/
HRESULT OpenFileDialog( std::wstring& strFilePath )
{
    IFileOpenDialog *pfd;
    
    // CoCreate the dialog object.
    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, 
                                  NULL, 
                                  CLSCTX_INPROC_SERVER, 
                                  IID_PPV_ARGS(&pfd));

    HWND hwnd = DXUTGetHWND();

    if (SUCCEEDED(hr))
    {
        COMDLG_FILTERSPEC spec[] =
        { 
            { L"DX11 Texture Files", L"*.bmp;*.jpg;*.jpeg;*.png;*.dds;*.tiff;*.gif;*.wmp" },
            { L"All", L"*.*" },
        };

        hr = pfd->SetFileTypes( sizeof( spec )/sizeof( COMDLG_FILTERSPEC ), spec );

        if (SUCCEEDED(hr))
        {
            // Show the Open dialog.
            hr = pfd->Show(hwnd);

            if (SUCCEEDED(hr))
            {
                // Obtain the result of the user interaction.
                IShellItem* pShellItem;
                hr = pfd->GetResult( &pShellItem );
                
                if (SUCCEEDED(hr))
                {
                    LPWSTR szFileName = NULL;
                    hr = pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &szFileName);
                    if( SUCCEEDED(hr) )
                    {
                        strFilePath = szFileName;
                    }
                    pShellItem->Release();
                }
            }
        }
        pfd->Release();
    }
    return hr;
}


/**
    CDXUTDialog callback.
*/
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
    switch( nControlID )
    {
        case IDC_MIDDLEKEY_SLIDER:
        {
            //CDXUTSlider* pSlider = ( CDXUTSlider* )pControl;
            g_gui.SetMiddleKeyValue();
            break;
        }

        case IDC_TONEMAP_ENABLE_CB:
        {
            CDXUTCheckBox* pCheckBox = ( CDXUTCheckBox* )pControl;
            g_toneMapCS.SetToneMapEnable( pCheckBox->GetChecked() );
            break;
        }

        case IDC_CONTROL_BURNOUT_CB:
        {
            CDXUTCheckBox* pCheckBox = ( CDXUTCheckBox* )pControl;
            g_toneMapCS.SetControlBurnOut( pCheckBox->GetChecked() );
            break;
        }

        case IDC_OPEN_FILE_DLG_BTN:
        {
            std::wstring strFilePath;
            if( SUCCEEDED( OpenFileDialog( strFilePath ) ) ) {
                // load new image
                g_hdrImageMgr.LoadImage( DXUTGetD3D11Device(), strFilePath );
                // recreate MeasureLuminance buffers to match new image width and height
                g_toneMapCS.GetpMeasureLuminanceCS()->OnResizedSwapChain( DXUTGetD3D11Device(), g_hdrImageMgr.GetWidth(), g_hdrImageMgr.GetHeight() );
            }
            break;
        }
    }
}

/**
*/
void GUI::SetMiddleKeyValue()
{
    g_toneMapCS.SetMiddleKey( ( 1.0f*m_pMiddleKeySlider->GetValue() )/MIDDLEKEY_SLIDER_MAX );
}

